<?php

namespace common\observer;

use common\model\TaskModel;
use support\SingletonTrait;
use common\model\EntityModel;
use common\model\ProjectModel;
use common\service\EntityService;
use common\service\CommonService;
use teamones\dbeventObserver\interfaces\SplSubject;
use teamones\dbeventObserver\interfaces\SplObserver;

/**
 * 任务分配执行方式发生变化 同步到实体(design,storyboard)
 */
class TaskExecutorTypeSyncToEntity implements SplObserver
{
    use SingletonTrait;

    /**
     * @inheritDoc
     */
    function update(SplSubject $subject): void
    {
        $updateData = $subject->getSplUpdateData();
        if (!isset($updateData['executor_type'])) {
            return;
        }
        $task = $subject->getSubjectData();
        if (empty($task['entity_id'])) {
            return;
        }
        // 外包项目不处理是否外包状态
        $projectType = model(ProjectModel::class)->where(['id' => $task['project_id']])->value('type');
        if ($projectType == ProjectModel::TYPE_OUTSOURCE) {
            return;
        }
        $entity = model(EntityModel::class)->find($task['entity_id']);
        if (empty($entity)) {
            return;
        }
        try {
            $this->checkEntityIsOutsourceStatus($entity);
        } catch (\Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
    }

    /**
     * 检查实体是否外包状态
     * @param $entity
     * @return void
     * @throws \think\Exception
     */
    public function checkEntityIsOutsourceStatus($entity)
    {
        // 获得实体列表
        $entityScoped = EntityService::getInstance()->getEntityScoped($entity);
        if (empty($entityScoped)) {
            return;
        }
        // 确定是否有外包
        $taskFilter = [
            'project_id' => $entity['project_id'],
            'step_type' => TaskModel::STEP_TYPE_STEP,
            'entity_id' => ['in', array_column($entityScoped, 'id')],
        ];
        $allExecuteType = model(TaskModel::class)
            ->where($taskFilter)
            ->field('executor_type')
            ->column('executor_type');
        if (empty($allExecuteType)) {
            return;
        }
        $isOutSideExecute = [TaskModel::EXECUTOR_TYPE_OUTSIDE, TaskModel::EXECUTOR_TYPE_TENANT_GROUP];
        $isinSideExecute = [TaskModel::EXECUTOR_TYPE_INSIDE,];
        $outsideExecuteList = array_filter($allExecuteType, function ($i) use ($isOutSideExecute) {
            return in_array($i, $isOutSideExecute);
        });
        $insideExecuteList = array_filter($allExecuteType, function ($i) use ($isinSideExecute) {
            return in_array($i, $isinSideExecute);
        });
        $hasOutsideExecute = !empty($outsideExecuteList);
        $hasInsideExecute = !empty($insideExecuteList);
        if (!$hasInsideExecute && !$hasOutsideExecute) {
            return;
        }
        
        $commonService = CommonService::instance('entity');
        foreach ($entityScoped as $entity) {
            $currentModuleData = module_by_id($entity['module_id']);
            $entityJsonFields = json_decode($entity['json'], true);
            $outsourceFieldName = $currentModuleData['code'] . '_is_outsource';
            $entityUpdateData = [
                'id' => $entity['id'],
                $outsourceFieldName => $hasOutsideExecute ? 'yes' : 'no',
            ];
            if (!empty($entityJsonFields[$outsourceFieldName])
                && $entityJsonFields[$outsourceFieldName] === $entityUpdateData[$outsourceFieldName]) {
                continue;
            }
            request()->getModuleCode($currentModuleData['code']);
            $commonService->setCurrentModuleCode($currentModuleData['code']);
            try {
                $commonService->update($entityUpdateData, $currentModuleData['code'], false);
            } catch (\Throwable $e) {
                trace(format_exception_info($e), 'ERR');
            }
        }
    }
}
